#ifndef     __DECODE_H
#define     __DECODE_H

#include "./types.h"
#include <string.h>
#include <utility>

namespace utils {

template <typename T>
inline 
std::enable_if_t< IS_INT<T> && (sizeof (T) == 1), T>
decode(const uint8_t *buf) {
    return static_cast<T>(buf[0]);
}

template <typename T>
inline 
std::enable_if_t< IS_INT<T> && (sizeof (T) == 2), T>
decode(const uint8_t *buf) {
    return static_cast<T>(
        (buf[0] << 8) +
        (buf[1])
    );
}

template <typename T>
inline 
std::enable_if_t< IS_INT<T> && (sizeof (T) == 4), T>
decode(const uint8_t *buf) {
    return static_cast<T>(
        (buf[0] << 24) +
        (buf[1] << 16) +
        (buf[2] << 8) +
        (buf[3])
    );
}

template <typename T>
inline 
std::enable_if_t<IS_ERROR<T>, T>
decode(const uint8_t *buf) {
    return Error(buf[0]);
}

template <typename T, typename... Ts>
inline bool decode_all(const uint8_t *buf, uint8_t size, T&& val, Ts&&... ts);

template <typename... Ts>
inline bool decode_next(const uint8_t *buf, uint8_t size, Ts&&... ts) {
    if constexpr (sizeof...(Ts) != 0) {
        return decode_all(buf, size, std::forward<Ts>(ts)...);
    } else {
        return true;
    }
}

template <typename T, typename... Ts>
inline bool decode_all(const uint8_t *buf, uint8_t size, T&& val, Ts&&... ts) {
    using TYPE = std::decay_t<T>;
    static_assert(IS_CODEC_TYPE<TYPE>, "decode type fail");

    if constexpr (IS_INT<TYPE> || IS_ERROR<TYPE>) {
        constexpr uint8_t len = sizeof (TYPE);
        if (size < len) {
            return false;
        }
        val = decode<TYPE>(buf);
        return decode_next(buf + len, size - len, std::forward<Ts>(ts)...);
    } else if constexpr (IS_BYTE_VIEW<TYPE>) {
        if (size < 1) {
            return false;
        }
        val.len = decode<uint8_t>(buf);
        uint8_t len = val.len + 1;
        if (size < len) {
            return false;
        }
        val.buf = buf + 1;
        return decode_next(buf + len, size - len, std::forward<Ts>(ts)...);
    } else {
        return false;
    }
}



}


#endif
